﻿using Hx.ADSyncPlatform.ActiveDirectory;
using Hx.ADSyncPlatform.ActiveDirectory.Model;
using Hx.ADSyncPlatform.Common.Excel;
using Hx.ADSyncPlatform.Common.ExportExcel;
using Hx.ADSyncPlatform.Controllers.Base;
using Hx.ADSyncPlatform.Infrastructure;
using Hx.ADSyncPlatform.Infrastructure.Page;
using Hx.ADSyncPlatform.Service;
using Hx.ADSyncPlatform.WebApi.Model;
using Masuit.Tools;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace Hx.ADSyncPlatform.Controllers
{
    /// <summary>
    /// 认证控制器
    /// </summary>
    [Route("api/ad/group")]
    [ApiController]
    [Authorize]
    public class GroupController : BaseController
    {
        private ActiveDirectoryClient activeDirectoryClient;

        private SystemConfig systemConfig;

        private Plat_DataPermissionService plat_DataPermissionService;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceProvider"></param>
        /// <param name="activeDirectoryClient"></param>
        public GroupController(IOptions<SystemConfig> myOptionsAccessor, Plat_DataPermissionService plat_DataPermissionService, IServiceProvider serviceProvider, ActiveDirectoryClient activeDirectoryClient) : base(serviceProvider)
        {
            this.activeDirectoryClient = activeDirectoryClient;
            this.systemConfig = myOptionsAccessor.Value;
            this.plat_DataPermissionService = plat_DataPermissionService;
            activeDirectoryClient.Groups.filterObjectByDataPermission = plat_DataPermissionService.FilterObjectHandler;

        }

        //[ResponseCache(Duration = 3600, Location = ResponseCacheLocation.Client)]
        /// <summary>
        /// 组列表 分页
        /// </summary>
        /// <param name="cn"></param>
        /// <returns></returns>
        [HttpGet("pageList")]
        public async Task<Result<PageResult<Group>>> PageList(string orgDN, string displayName, string searchScope, [FromQuery] Pagination pagination)
        {
            List<string> systemOus = systemConfig.systemOU.Select(n => n.name).ToList();
            PageResult<Group> groups = activeDirectoryClient.Groups.PageList(orgDN, displayName, systemConfig, platManager.DataPermissions, searchScope, pagination.pageNum, pagination.pageSize);

            return await base.Success<PageResult<Group>>(groups);

        }


        /// <summary>
        /// 根据组织找组成员数据源
        /// </summary>
        /// <param name="cn"></param>
        /// <returns></returns>
        [HttpGet("members")]
        public async Task<Result<List<DirectoryObject>>> GroupMembers(string displayName, string orgDN = null)
        {
            List<DirectoryObject> directoryObjects = new List<DirectoryObject>();


            directoryObjects = activeDirectoryClient.Groups.SearchMembers(displayName, orgDN, systemConfig.group, systemConfig.person);

            return await base.Success<List<DirectoryObject>>(directoryObjects);

        }

        /// <summary>
        /// 搜索组成员数据源
        /// </summary>
        /// <param name="account"></param>
        /// <param name="mail"></param>
        /// <param name="department"></param>
        /// <returns></returns>
        [HttpGet("searchMembers")]
        public async Task<Result<List<DirectoryObject>>> SearchGroupMembers(string account = null, string mail = null, string department = null)
        {
            List<DirectoryObject> directoryObjects = new List<DirectoryObject>();
            List<string> systemOus = systemConfig.systemOU.Select(n => n.name).ToList();
            directoryObjects = activeDirectoryClient.Groups.SearchMembersByCondition(account, mail, department, platManager.DataPermissions, systemOus);

            return await base.Success<List<DirectoryObject>>(directoryObjects);

        }



        /// <summary>
        /// 组成员 分页
        /// </summary>
        /// <param name="cn"></param>
        /// <returns></returns>
        [HttpGet("{distinguishedName}/membersPage")]
        public async Task<Result<PageResult<DirectoryObject>>> GroupMembersPage([FromQuery] Pagination pagination,
            string displayName, [FromRoute] string distinguishedName)
        {

            PageResult<DirectoryObject> directoryObjects = activeDirectoryClient.Groups.MembersPageList(distinguishedName, displayName, pagination);

            return await base.Success<PageResult<DirectoryObject>>(directoryObjects);

        }



        /// <summary>
        /// 组信息
        /// </summary>
        /// <param name="samAccountName"></param>
        /// <returns></returns>
        [HttpGet("{samAccountName}/info")]
        public async Task<Result<Group>> Get([FromRoute] string samAccountName)
        {
            Group person = activeDirectoryClient.Groups.Single(samAccountName);

            return await base.Success<Group>(person);

        }

        /// <summary>
        /// 添加组
        /// </summary>
        /// <param name="samAccountName"></param>
        /// <returns></returns>
        [HttpPost("add")]
        public async Task<Result<bool>> Add(string orgDN, [FromBody] Group group)
        {
            bool success = activeDirectoryClient.Groups.Create(orgDN, systemConfig, group);
            return await base.Success<bool>(success);

        }

        /// <summary>
        /// 删除组
        /// </summary>
        /// <param name="samAccountName"></param>
        /// <returns></returns>
        [HttpDelete("{samAccountName}")]
        public async Task<Result<bool>> Delete([FromRoute] string samAccountName)
        {
            bool success = activeDirectoryClient.Groups.Delete(samAccountName);
            return await base.Success<bool>(success);

        }
        /// <summary>
        /// 导出Excel
        /// </summary>
        [HttpPost("exportExcel")]
        public async Task<object> ExportGroupExcel(string orgDN, string displayName, string searchScope)
        {
            try
            {
                List<string> systemOus = systemConfig.systemOU.Select(n => n.name).ToList();
                //获取组
                List<Group> groups = activeDirectoryClient.Groups.Get(orgDN, displayName, systemConfig.group, platManager.DataPermissions, systemOus, searchScope);

                if (!groups.Any()) return await base.Fail("导出失败！");

                List<ExportGroupModel> GroupModelData = mapper.Map<List<ExportGroupModel>>(groups);
                //组人员集合
                List<ExportGroupPersonModel> GroupPersonModelList = new List<ExportGroupPersonModel>();
                //遍历组
                foreach (var item in groups)
                {
                    if (item.Member != null)
                    {
                        //取成员信息
                        foreach (var items in item.Member)
                        {
                            GroupPersonModelList.Add(new ExportGroupPersonModel { sAMAccountName = item.CN, distinguishedName = items, cn = items.Split(',')[0].Split('=')[1] });
                        }
                    }
                }
                TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
                string excelName = $"Group{Convert.ToInt64(ts.TotalSeconds)}.xlsx";
                List<(string, List<object>)> tuples =
                new List<(string, List<object>)>();
                tuples.Add(("组", GroupModelData.Select(d => (object)d).ToList()));
                tuples.Add(("组成员", GroupPersonModelList.Select(d => (object)d).ToList()));
                var stream = ExcelHelper.ExportExcels(tuples);
                if (stream != null)
                {
                    return File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", excelName);
                }
                return await base.Fail("导出失败！");
            }
            catch (Exception ex)
            {
                return await base.Fail(ex.Message);
            }
        }


        [AllowAnonymous]
        /// <summary>
        /// 模板下载
        /// </summary>
        /// <returns></returns>
        [HttpGet("downloadGroupTemplate")]
        public async Task<object> DownloadGroupTemplate()
        {
            try
            {
                string folderPath = AppSettings.Configuration.GetValue<string>("TemplateFolder");
                var FilePath = $"{folderPath}添加组成员模板.xlsx";
                var stream = System.IO.File.OpenRead(FilePath);
                return File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", Path.GetFileName(FilePath));
            }
            catch (Exception ex)
            {

                return await base.Fail(ex.Message);
            }
        }
        /// <summary>
        /// 上传
        /// </summary>
        /// <returns></returns>
        [HttpPost("ImportGroupTemplate")]
        public async Task<object> importGroupTemplate(IFormFile filev, [FromForm] bool isNew = false)
        {
            var Files = Request.Form.Files[0];
            string distinguishedName = Request.Form["distinguishedName"];
            var webRootPath = AppSettings.Configuration.GetSection("UploadPath").Get<string>();
            string fullPath = ExcelHelper.SaveExcel(Files, webRootPath);
            List<Person> people = new List<Person>();
            #region 打开读取excel文件中的数据
            if (System.IO.File.Exists(fullPath))
            {
                List<ImportPersonStateModel> personData = new List<ImportPersonStateModel>();
                using (FileStream file = new FileStream(fullPath, FileMode.Open, FileAccess.Read))
                {
                    //获取需要被导入的excel工作薄
                    IWorkbook workBook = new XSSFWorkbook(file);
                    //判断Excel文件中有几个sheet表数据
                    if (workBook.NumberOfSheets > 0)
                    {
                        #region 开始循环读取sheet表中的数据 
                        for (int v = 0; v < workBook.NumberOfSheets; v++)
                        {
                            //声明行变量
                            IRow row = null;
                            //声明sheet表变量
                            ISheet sheet = null;
                            //拿到Sheet数据表以后，遍历获取数据
                            sheet = workBook.GetSheetAt(v);
                            for (int i = 0; i < sheet.LastRowNum + 1; i++)
                            {
                                //说明：
                                //i=0      拿到的是excel列字段名称
                                //i>=1   拿到的是excel的行数据
                                //首先拿到excel第一行列字段属性名，进行判断是否符合导入数据库的模板规范
                                try
                                {
                                    if (i == 0)
                                    {
                                        row = sheet.GetRow(i);
                                        if (row.Cells[0].StringCellValue != "账号")
                                            return await base.Fail("模板不匹配！");
                                    }
                                    else
                                    {
                                        //获取excel表中非 列名称属性的数据集合
                                        row = sheet.GetRow(i);
                                        ImportPersonStateModel persons = new ImportPersonStateModel();
                                        if (string.IsNullOrEmpty(row.Cells[0].StringCellValue))
                                        {
                                            persons.importState = "失败";
                                            persons.errorMsg = $"请输入账号";
                                            personData.Add(persons);
                                            continue;
                                        }
                                        //存入结果数据状态集合
                                        persons.SamAccountName = row.Cells[0].StringCellValue;
                                        //效验人员是否存在
                                        Person person = activeDirectoryClient.Persons.Single(row.Cells[0].StringCellValue);
                                        if (person == null)
                                        {
                                            persons.importState = "失败";
                                            persons.errorMsg = $"用户{row.Cells[0].StringCellValue}不存在";
                                            personData.Add(persons);
                                            continue;
                                        }
                                        persons.DistinguishedName = person.DistinguishedName;
                                        persons.importState = "成功";
                                        personData.Add(persons);
                                        people.Add(person);
                                    }
                                }
                                catch
                                {
                                    //关闭工作薄资源
                                    workBook.Close();
                                    //清楚缓冲区
                                    file.Flush();
                                    //释放内存
                                    file.Dispose();
                                    return await base.Fail("sheet名为[" + workBook.GetSheetAt(v).SheetName + " ]导入数据出错，请检查 账号为[" + row.Cells[0].StringCellValue + "]记录！");

                                }
                            }

                            #endregion
                        }
                        var resultPersonData = personData.Where(c => c.importState == "成功").Select(c => c.DistinguishedName).ToList();

                        if (resultPersonData.Any())
                        {
                            if (isNew)
                            {
                                return await base.Success<List<Person>>(people);
                            }
                            else
                            {
                                activeDirectoryClient.Groups.AddMember(distinguishedName, resultPersonData);
                                return await base.Success<List<ImportPersonStateModel>>(personData);
                            }
                        }
                        else
                        {
                            return await base.Fail<List<ImportPersonStateModel>>("未匹配到人员！");
                        }
                    }
                    else
                    {
                        return await base.Fail("Excel文件中没有sheet表数据，无法导入数据库，请仔细检查文件！");
                    }

                }
                return await base.Success<List<ImportPersonStateModel>>(personData);
            }
            else
            {
                return await base.Fail("没有找到文件，插入操作失败！");
            }
            #endregion
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="distinguishedName"></param>
        /// <param name="text"></param>
        /// <param name="isNew"></param>
        /// <returns></returns>
        [HttpPost("importMemberFromClipboard")]
        public async Task<object> ImportMemberFromClipboard(string distinguishedName = "", string text = "", bool isNew = false)
        {
            try
            {
                List<ImportPersonStateModel> personData = new List<ImportPersonStateModel>();
                List<Person> people = new List<Person>();
                text = text.Replace(";", ";").Replace(",", ",").Replace("(", "(").Replace(")", ")");

                List<string> rows = text.Split("\n").Where(n => !string.IsNullOrWhiteSpace(n)).ToList();
                foreach (var item in rows)
                {
                    ImportPersonStateModel persons = new ImportPersonStateModel();
                    if (string.IsNullOrEmpty(item))
                    {
                        persons.importState = "失败";
                        persons.errorMsg = $"请输入账号";
                        personData.Add(persons);
                        continue;
                    }

                    Person person = activeDirectoryClient.Persons.Single(item);
                    //存入结果数据状态集合
                    persons.SamAccountName = item;
                    if (person == null)
                    {
                        persons.importState = "失败";
                        persons.errorMsg = $"用户{item}不存在";
                        personData.Add(persons);
                        continue;
                    }
                    persons.DistinguishedName = person.DistinguishedName;
                    persons.importState = "成功";
                    personData.Add(persons);
                    people.Add(person);
                }
                var resultPersonData = personData.Where(c => c.importState == "成功").Select(c => c.DistinguishedName).ToList();

                if (resultPersonData.Any())
                {
                    if (isNew)
                    {
                        return await base.Success<List<Person>>(people);
                    }
                    else
                    {
                        activeDirectoryClient.Groups.AddMember(distinguishedName, resultPersonData);
                        return await base.Success<List<ImportPersonStateModel>>(personData);
                    }
                }
                else
                {
                    return await base.Fail<List<ImportPersonStateModel>>("未匹配到人员！");
                }

            }
            catch (Exception ex)
            {

                return await base.Fail<List<Person>>("文本校验失败，请检查文本是否符合要求！");
            }

        }


        [HttpPost("{distinguishedName}/addGroupMember")]
        public async Task<Result> AddGroupMember([FromRoute] string distinguishedName
    , [FromBody] Dictionary<string, List<string>> data)
        {
            if (data.ContainsKey("members"))
            {
                List<string> members = data["members"];
                activeDirectoryClient.Groups.AddMember(distinguishedName, members);
                return await base.Success();
            }
            return await base.Fail("未指定移除的组成员！");
        }

        [HttpDelete("{distinguishedName}/removeGroupMember")]
        public async Task<Result> RemoveGroupMember([FromRoute] string distinguishedName
            , [FromBody] Dictionary<string, List<string>> data)
        {
            if (data.ContainsKey("members"))
            {
                List<string> members = data["members"];
                activeDirectoryClient.Groups.RemoveMember(distinguishedName, members);
                return await base.Success();
            }
            return await base.Fail("未指定移除的组成员！");
        }

    }
}